#include "squad.h"


squad::squad(void)
{
}

// Initializes squad proprties based on agent type
squad::squad(team_T iTeam, shape_T iType, vertex iPosition) {

	int i;
	vertex tempPosition;

	team = iTeam;
	selected = false;
	attacking  = false;
	aggressive = true;
	exploring = false;
	expInterval = GOALSHIFTTIME;
	expTimer = 0;
	
	// TODO - determine validity of starting position

	switch (iType) {
	case TRIANGLE:

		// Set type property
		type = TRIANGLE;

		// Set Boids properties
		sepRange    = (float)15;    sepModifier    = (float)0.01;
		avoidRange  = (float)3;     avoidModifier  = (float)0.01;
		cohRange    = (float)30;    cohModifier    = (float)0.0001;
		aliRange    = (float)30;    aliModifier    = (float)0.003;
		borRange    = (float)50,    borModifier    = (float)0.0001;
		obsRange    = (float)1;   obsModifier    = (float)0.01;
		goalRange   = (float)200,   goalModifier   = (float)0.000001;
		attackRange = (float) 30;

		// Set Agent list properties
		maxAgents = 2;

		// Set cost of individual units
		unitPopCost = 1;

		// Initialize squad agents (randomly distributed around squar starting point)
		triangleAgent * tempTriangle;
		for (i = 0; i < maxAgents; i++) {
			tempPosition = vertex(iPosition.x+randRange(-1,1), iPosition.y+randRange(-1,1));
			tempTriangle = new triangleAgent(tempPosition, AVector(0,0), 3, iTeam);
			agentList.push_back(tempTriangle);
		}

		break;

	case CIRCLE:

		// Set type property
		type = CIRCLE;

		// Set Boids properties
		sepRange    = (float)15;    sepModifier    = (float)0.001;
		avoidRange  = (float)3;     avoidModifier  = (float)0.01;
		cohRange    = (float)30;    cohModifier    = (float)0.0001;
		aliRange    = (float)30;    aliModifier    = (float)0.003;
		borRange    = (float)50,    borModifier    = (float)0.0001;
		obsRange    = (float)1;   obsModifier    = (float)0.01;
		goalRange   = (float)200,   goalModifier   = (float)0.000001;
		attackRange = (float) 20;

		// Set Agent list properties
		maxAgents = 4;

		// Set cost of individual units
		unitPopCost = 1;

		// Initialize squad agents (randomly distributed around squar starting point)
		circleAgent * tempCircle;
		for (i = 0; i < maxAgents; i++) {
			tempPosition = vertex(iPosition.x+randRange(-1,1), iPosition.y+randRange(-1,1));
			tempCircle = new circleAgent(tempPosition, AVector(0,0),3, iTeam);
			agentList.push_back(tempCircle);
		}

		break;

	case RECTANGLE:

		// Set type property
		type = RECTANGLE;

		// Set Boids properties
		sepRange    = (float)30;    sepModifier    = (float)0.005;
		avoidRange  = (float)3;     avoidModifier  = (float)0.01;
		cohRange    = (float)30;    cohModifier    = (float)0.0001;
		aliRange    = (float)30;    aliModifier    = (float)0.003;
		borRange    = (float)50,    borModifier    = (float)0.0001;
		obsRange    = (float)1;   obsModifier    = (float)0.01;
		goalRange   = (float)200,   goalModifier   = (float)0.000001;
		attackRange = (float) 15;

		// Set Agent list properties
		maxAgents = 3;

		// Set cost of individual units
		unitPopCost = 3;

		// Initialize squad agents (randomly distributed around squar starting point)
		rectangleAgent * tempRectangle;
		for (i = 0; i < maxAgents; i++) {
			tempPosition = vertex(iPosition.x+randRange(-1,1), iPosition.y+randRange(-1,1));
			tempRectangle = new rectangleAgent(tempPosition, AVector(0,0),3, iTeam);
			agentList.push_back(tempRectangle);
		}

		break;
	}

	goalList.clear();
}


squad::~squad(void)
{
	unsigned int i;
	for (i = 0; i < agentList.size(); i++) delete agentList[i];
}

// Return map terrain segment (node) that the squad's centroid lies on
mapNode squad::mapPosition(Terrain * map) {

	int i;
	int agentCount = agentList.size();
	agent * tempAgent;
	vertex squadCenter = vertex();

	for (i=0; i < agentCount; i++) {
		tempAgent = agentList[i];
		squadCenter.x += tempAgent->position.x;
		squadCenter.y += tempAgent->position.y;
	}

	// Resulting world coordinates
	squadCenter = squadCenter / agentCount;

	//Map to terrain segment
	squadCenter = map->GetTerrainPoint(squadCenter);

	return mapNode(squadCenter.x, squadCenter.y);
}

/*
// Return map terrain segment (node) that the squad's goal lies on
mapNode squad::goalPosition(Terrain * map) {

	return map->GetTerrainPoint(goal);
}
*/

// Check if any of squad units are in a specific selection box
bool squad::isBoxSelected(float left, float right, float bottom, float top) {
	int i;
	vertex tempPos;
	int agentCount = agentList.size();
	
	for (i=0; i < agentCount; i++) {
		tempPos = agentList[i]->position;

		if (tempPos.x >= left &&
			tempPos.x <= right &&
			tempPos.y >= bottom &&
			tempPos.y <= top) {
			return true;
		}
	}
	return false;
}

// This returns true under 2 conditions:
// * The squad has collectively reached its current waypoint goal
// * The squad is currently closer to its next waypoint than the current one
bool squad::updateGoal(Terrain * map) {

	int i;
	int agentCount = agentList.size();
	agent * tempAgent;
	vertex squadCenter = vertex();
	vertex goalNode = goalList.front();
	float distance;

	for (i=0; i < agentCount; i++) {
		tempAgent = agentList[i];
		squadCenter.x += tempAgent->position.x;
		squadCenter.y += tempAgent->position.y;
	}

	// Resulting world coordinates
	squadCenter = squadCenter / agentCount;

	distance = (goalNode - squadCenter).length();

	int testsize = goalList.size();
	if (distance < 5) 
		return true;
	//Additional condition - when next goal waypoint is closer than the current
	else if (goalList.size() > 1) {

		list<vertex>::iterator  goalIter = goalList.begin();
		goalIter++;
		vertex nextGoal = *goalIter;
		float distance2 = (nextGoal - squadCenter).length();
		if (distance2 < distance) 
			return true;
	}
	
	return false;
}

bool squad::isExploring(void) {return exploring;}

void squad::activateExplore(Terrain * map) {
	exploring = true;
	expTimer = 0;
	goalList.clear();
	goalList.push_back(randomMapPoint(map));
}

void squad::deactivateExplore(void) {
	exploring = false;
	goalList.clear();
}

vertex squad::randomMapPoint(Terrain * map) {
	float xMax=WIDTH/2; float xMin = -WIDTH/2;
	float yMax=HEIGHT/2; float yMin = -HEIGHT/2;
	bool validPoint = false;
	vertex point;
	while (!validPoint) {
		point = vertex(randRange(xMin,xMax),randRange(yMin,yMax));
		vertex terrainPoint = map->GetTerrainPoint(point);
		validPoint = map->validCell(terrainPoint.x,terrainPoint.y);
	}
	return point;
}